﻿using System;
using System.Collections.Generic;
using System.Text;
using SdmxMl.Common;
using SdmxMl.Structure;
using SdmxMl.Manager;

namespace SasPlugIn.SASCli
{
    /// <summary>
    /// Helper to store code and format associated to a variable
    /// </summary>
    internal class CodeAndVarFormat
    {
        public TextFormatType Tft { get; set; }
        public CodeListType Codelist { get; set; }
        public string FormatId { get; set; }

        public CodeAndVarFormat(TextFormatType txtFmt, CodeListType clt, string id)
        {
            Tft = txtFmt;
            Codelist = clt;
            FormatId = id;
        }
    }
    /// <summary>
    /// Class for SAS instructions of type FORMAT in order to provide
    /// texts for codes and variables
    /// </summary>
    public class FormatExport
    {
        #region Internal members

        private IomProperties properties;
        private Dictionary<string, CodeAndVarFormat> dicoCodelist;
        private RefVarHelper refVar;
        private List<BaseDimensionType> listVar;
        private bool useAbbreviation;
        private List<string> formatLanguages;


        #endregion

        public FormatExport(SmManager smMgr, KeyFamilyType dsd, IomProperties prop, bool useAbbrev, List<string> fmtLanguages)
        {
            try
            {
                useAbbreviation = useAbbrev;
                properties = prop;
                formatLanguages = fmtLanguages;

                refVar = new RefVarHelper(smMgr);

                // Prepare list, ignore flag speciality
                listVar = refVar.PrepareVarList(dsd, true);
            }
            catch (Exception ex)
            {
                throw new ApplicationException("Unable to prepare variable list for DSD. Reason: " + ex.Message);
            }
        }

        private void PrepareDicoCodelist()
        {
            dicoCodelist = new Dictionary<string, CodeAndVarFormat>();
            foreach (BaseDimensionType bdt in listVar)
            {
                // Get associated var type (direct in DSD or via concept if missing in DSD)
                CodeListType clt = refVar.GetCodelistOfBaseDim(bdt);

                if (clt != null)
                {
                    // The associated format
                    TextFormatType tft = refVar.GetTextFormatTypeOfBaseDim(bdt);
                    if (tft.TextType == TextTypeType.Undefined)
                        tft = clt.GetDefaultTextFormat();

                    // Update dictionary
                    if (dicoCodelist.ContainsKey(clt.FullIdent) == false)
                        dicoCodelist.Add(clt.FullIdent, new CodeAndVarFormat(tft, clt, bdt.Id));
                }
            }
        }

        public StringBuilder GenFormat(DataLinkParameters dataLinkParam)
        {
            // Prepare list if not yet done
            if (dicoCodelist == null)
                PrepareDicoCodelist();

            // Use default format menbers
            FormatCodeAttributes fmt = new FormatCodeAttributes(useAbbreviation);

            StringBuilder sb = new StringBuilder();
            sb.Append("libname meta \"").Append(dataLinkParam.FormatLibraryPath).Append(" \" ;").Append(Environment.NewLine);
            sb.Append("PROC FORMAT LIBRARY=").Append(properties.TablePrefix).Append(" ;").Append(Environment.NewLine);
            foreach (CodeAndVarFormat cvf in dicoCodelist.Values)
            {
                CodeListFormat clFormat = new CodeListFormat(formatLanguages, fmt);
                clFormat.FillCodelistFormat(sb, cvf.Codelist, cvf.Tft, cvf.FormatId);
            }

            sb.Append("RUN;").Append(Environment.NewLine);

            return sb;
        }
        public StringBuilder GenLinkAndLabel(DataLinkParameters dataLinkParam, string lg)
        {
             // Prepare list if not yet done
            if (dicoCodelist == null)
                PrepareDicoCodelist();

            StringBuilder sb = new StringBuilder();

            // Parameters definition
            sb.Append("%let p_lib_fmt=").Append(dataLinkParam.FormatLibraryPath).Append(" ;").Append(Environment.NewLine);
            sb.Append("%let p_lib_in=").Append(dataLinkParam.DataEntryLibraryPath).Append(" ;").Append(Environment.NewLine);
            sb.Append("%let p_lib_out=").Append(dataLinkParam.DataOutputLibraryPath).Append(" ;").Append(Environment.NewLine);
            sb.Append("%let p_file_in=").Append(dataLinkParam.DataSetEntryName).Append(" ;").Append(Environment.NewLine);
            sb.Append("%let p_file_out=").Append(dataLinkParam.DataSetOutputName).Append(" ;").Append(Environment.NewLine);
            sb.Append(Environment.NewLine);

            sb.Append("libname meta").Append("      \"&p_lib_fmt.\" ;").Append(Environment.NewLine);
            sb.Append("libname lib_in    \"&p_lib_in.\" ;").Append(Environment.NewLine);
            sb.Append("libname lib_out   \"&p_lib_out.\" ;").Append(Environment.NewLine);
 
            sb.Append("options fmtsearch=(work ").Append(properties.TablePrefix).Append(");").Append(Environment.NewLine);
            sb.Append(Environment.NewLine);
 
            sb.Append("DATA  lib_out.&p_file_out. ; ").Append(Environment.NewLine);
            sb.Append("set lib_in.&p_file_in.   ;").Append(Environment.NewLine);
            sb.Append(Environment.NewLine);

            // Format link
            foreach (BaseDimensionType bdt in listVar)
            {
                // Get associated var type (direct in DSD or via concept if missing in DSD)
                CodeListType clt = refVar.GetCodelistOfBaseDim(bdt);
                if (clt != null)
                {
                    CodeAndVarFormat cVarFormat = dicoCodelist[clt.FullIdent];
                    sb.Append("FORMAT ").Append(bdt.Id).Append(" ");
                    sb.Append(cVarFormat.FormatId).Append('_').Append(lg).Append(". ;").Append(Environment.NewLine);
                }
            }

            // Labels
            sb.Append("LABEL").Append(Environment.NewLine);
            foreach (BaseDimensionType bdt in listVar)
            {
                sb.Append(bdt.Id).Append("=");
                ConceptType concept = refVar.GetConcept(bdt.Id, bdt.ConceptSchemeInfo);
                string label = concept.Name.GetForLanguage(lg);
                if (useAbbreviation && concept.AnnotationList.Count > 0)
                {
                    Annotation a = concept.AnnotationList.GetAnnotationType("ABBREV");
                    if (a != null)
                        label = a.Text.GetForLanguage(lg);
                }
                sb.Append(QuoteStr(label)).Append(Environment.NewLine);
            }
            sb.Append(";RUN;");



            return sb;
        }

        private string QuoteStr(string s)
        {
            return "\"" + s + "\"";
        }


    }
}
